{-# LANGUAGE TypeFamilies, TypeOperators, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
{- |
Module      :  ObsData
Description :  <optional short text displayed on contents page>
Copyright   :  (c) Sergey Sichevskiy 2012
License     :  BSD3

Maintainer  :  s.sichevskij@gmal.com
Stability   :  experimental
Portability :  portable

-}

module ObsData 
 ( ObsData(..)
 , genModel
 , genModel2
 ) where

import Types
import Data.HList
import Control.Applicative (liftA2, pure )

genModel :: ObsData a => a -> Factory (Data a, SED -> Data a)
genModel o = do
   d <- toInitalData o
   f <- toModelData o
   return (d, f)

--
genModel2 :: (ObsData a, Data a ~ [b]) => [a] -> Factory ([b], SED -> [b])
genModel2 o = do
  d <- getData  o
  f <- getModel o
  return (d,f)

  where
    --getData :: [AnyObsData] -> Factory [AnyPhotometry]
    getData xs = foldl (liftA2 (++)) (pure []) $ map toInitalData xs

    --getModel :: [AnyObsData] -> Factory (SED -> [AnyPhotometry])
    getModel xs = foldl (liftA2 $ liftA2 (++)) (pure $ const []) $ map toModelData xs

-- |Класс наблюдаемые данных
class ObsData a where

 -- Моделируемые данные
  type Data a :: * 

  -- Отображение наблюдаемых данных в данные, которые моделируются в
  -- конкретной модели, применяемой в процессе "фитирования".
  toInitalData :: a -> Factory (Data a)

  -- Отображение наблюдаемых данных в функцию, которая по распределению
  -- энергии в спектре вычисляет соответствующие модельный данные.
  toModelData  :: a -> Factory (SED -> Data a)


instance  ObsData Null where
  type Data Null = Null

  toInitalData _ = return $ Null
  toModelData  _ = return $ const Null

instance ( ObsData o
         , ObsData os
         , HAppend (Data o) (Data os)
         )
      =>   ObsData (o ::: os)
 where
  type Data (o ::: os) = Append (Data o) (Data os)

  toInitalData (o ::: os) = liftA2 (hAppend)  (toInitalData o) (toInitalData os)
  toModelData  (o ::: os) = liftA2 (liftA2 (hAppend)) (toModelData  o) (toModelData  os)